package pl.kosmowska.ewelina.client.app.activity;


import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import pl.kosmowska.ewelina.client.Constants;
import pl.kosmowska.ewelina.client.ViewMessages;
import pl.kosmowska.ewelina.client.app.ClientFactory;
import pl.kosmowska.ewelina.client.app.activity.places.OutcomeEditPlace;
import pl.kosmowska.ewelina.client.app.activity.places.OutcomePlace;
import pl.kosmowska.ewelina.client.app.activity.places.SignInPlace;
import pl.kosmowska.ewelina.client.app.requestfactory.OutcomeDataRequest;
import pl.kosmowska.ewelina.client.app.requestfactory.dto.OutcomeDataProxy;
import pl.kosmowska.ewelina.client.app.requestfactory.dto.SavingsDataProxy;
import pl.kosmowska.ewelina.client.app.user.AuthEvent;
import pl.kosmowska.ewelina.client.app.user.AuthEvent.Auth;
import pl.kosmowska.ewelina.client.app.user.AuthEventHandler;
import pl.kosmowska.ewelina.client.views.OutcomeView;

import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.place.shared.Place;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.google.web.bindery.requestfactory.shared.Request;
import com.google.web.bindery.requestfactory.shared.ServerFailure;

public class OutcomeActivity extends AbstractActivity implements OutcomeView.Presenter {

	private OutcomeView view;
	private ClientFactory clientFactory;

	public OutcomeActivity(OutcomePlace place, ClientFactory clientFactory) {
		this.clientFactory = clientFactory;
	}


	@Override
	public void start(AcceptsOneWidget containerWidget, EventBus eventBus) {
		view = clientFactory.getOutcomeView();
		view.setPresenter(this);
		initAuthorisationForView();
		startView();
		containerWidget.setWidget(view.asWidget());
	}


	private void startView() {
		if (clientFactory.getIsLoggedIn() == null) {
			// wait for login event b/c hasn't happened yet
		} else if (clientFactory.getIsLoggedIn() == true) {
			loadDataForOutcomeView();
		} else if (clientFactory.getIsLoggedIn() == false) { 
			goTo(new SignInPlace());
		}
	}
	
	public void goTo(Place place) {
		clientFactory.getPlaceController().goTo(place);
	}
	
	@Override
	public void goToNewOutcomePlace() {
		clientFactory.getPlaceController().goTo(new OutcomeEditPlace(Constants.OUTCOME));
	}

	private void initAuthorisationForView() {
		
		if (view.isAlreadyInit() == false) {
			clientFactory.getEventBus().addHandler(AuthEvent.TYPE, new AuthEventHandler() {
				public void onAuthEvent(AuthEvent event) {
					Auth e = event.getAuthEvent();
					if (e == Auth.LOGGEDIN) {
						loadDataForOutcomeView();
					} else if (e == Auth.LOGGEDOUT) {
						goTo(new SignInPlace());
					}
				}
			});
		}
		view.setAlreadyInit(true);
	}

	@Override
	public void loadDataForOutcomeView(Date startDate, Date endDate) {
		clientFactory.getAppLoadingView().startProcessing();
		Request<List<OutcomeDataProxy>> req = clientFactory.getRequestFactory().getOutcomeDataRequest().findOutcomeDataByUserBetweenDates(true, startDate, endDate);
		req.fire(new Receiver<List<OutcomeDataProxy>>() {
			public void onSuccess(List<OutcomeDataProxy> returnedOutcomeData) {
				processOutcomeList(returnedOutcomeData);
				clientFactory.getAppLoadingView().stopProcessing();
			}
			public void onFailure(ServerFailure error) {
				super.onFailure(error);
				clientFactory.getAppLoadingView().stopProcessing();
			}
		});

	}

	@Override
	public void loadDataForOutcomeView() {
		clientFactory.getAppLoadingView().startProcessing();
		Receiver<List<OutcomeDataProxy>> receiver= new Receiver<List<OutcomeDataProxy>>() {
			public void onSuccess(List<OutcomeDataProxy> returnedOutcomeData) {
				processOutcomeList(returnedOutcomeData);
				clientFactory.getAppLoadingView().stopProcessing();
			}
			public void onFailure(ServerFailure error) {
				super.onFailure(error);
				clientFactory.getAppLoadingView().stopProcessing();
			}
		};
		Request<List<OutcomeDataProxy>> req = clientFactory.getRequestFactory().getOutcomeDataRequest().findOutcomeDataByUser(true,new Date());
		req.fire(receiver);

	}

	
	public void processOutcomeList(List<OutcomeDataProxy> returnedOutcomeData) {
		if (returnedOutcomeData == null || returnedOutcomeData.size() == 0) {
			view.showMessage(ViewMessages.NO_DATA_TO_SHOW);
			view.clearView();
		}else{			
			view.reInitView(returnedOutcomeData);
		}
	}
	

	
	private float round (double val)
	{
		double exp = Math.pow(10, 2);
		double rounded = val * exp;
		rounded = Math.round(rounded);
		return (float)(rounded / exp);
	}

	@Override
	public void deleteSingleOutcome(final OutcomeDataProxy outcomeDataProxy) {
		Request<Boolean> req = clientFactory.getRequestFactory().getOutcomeDataRequest().deleteById(outcomeDataProxy.getId());
		req.fire(new Receiver<Boolean>() {
			public void onSuccess(Boolean data) {
				if (data != null && data.booleanValue() == true) {
					view.updateAfterOutcomeDelete(outcomeDataProxy);
				} else {
					view.showMessage(ViewMessages.ERROR_ON_DELETE);
				}
			}
			public void onFailure(ServerFailure error) {
				super.onFailure(error);
			}
		});

	}

	@Override
	public void deleteFollowingMultipleOutcome(OutcomeDataProxy outcomeDataProxy) {
		clientFactory.getRequestFactory().getOutcomeDataRequest().deleteRepeatedOutcomeData(outcomeDataProxy.getGroupKey(), outcomeDataProxy.getDate()).fire(new Receiver<List<OutcomeDataProxy>>() {
			public void onSuccess(List<OutcomeDataProxy> deletedList) {
				if (deletedList != null && !deletedList.isEmpty()) {
					view.updateAfterOutcomeDelete(deletedList);
				} else {
					view.showMessage(ViewMessages.ERROR_ON_DELETE);
				}
			}
			public void onFailure(ServerFailure error) {
				super.onFailure(error);
			}
		}); 

	}

	@Override
	public void deleteAllMultipleOutcome(OutcomeDataProxy outcomeDataProxy) {
		clientFactory.getRequestFactory().getOutcomeDataRequest().deleteRepeatedOutcomeData(outcomeDataProxy.getGroupKey(), null).fire(new Receiver<List<OutcomeDataProxy>>() {
			public void onSuccess(List<OutcomeDataProxy> deletedList) {
				if (deletedList != null && !deletedList.isEmpty()) {
					view.updateAfterOutcomeDelete(deletedList);
				} else {
					view.showMessage(ViewMessages.ERROR_ON_DELETE);
				}
			}
			public void onFailure(ServerFailure error) {
				super.onFailure(error);
			}
		}); 
	}

	@Override
	public void deleteSavingsPlan(String sponsoredOutcomeDataId) {
		Request<Boolean> req = clientFactory.getRequestFactory().getSavingsDataRequest().deleteSavingsData(sponsoredOutcomeDataId);
		req.fire(new Receiver<Boolean>() {
			public void onSuccess(Boolean data) {
				if (data != null && data.booleanValue() == true) {
				} else {
					view.showMessage(ViewMessages.ERROR_ON_DELETE);
				}
			}
			public void onFailure(ServerFailure error) {
				super.onFailure(error);
			}
		});

	}


	@Override
	public void reInitSavingsPlan(final OutcomeDataProxy outcomeDataProxy) {
		Request<SavingsDataProxy> req = clientFactory.getRequestFactory().getSavingsDataRequest().findSavingsData(outcomeDataProxy.getGroupKey());
		req.fire(new Receiver<SavingsDataProxy>() {
			public void onSuccess(SavingsDataProxy returnedSavingsData) {
				if(returnedSavingsData!=null)
					getSavingsOutcomeList(returnedSavingsData, outcomeDataProxy);
			}
			public void onFailure(ServerFailure error) {
				super.onFailure(error);
			}
		});

	}

	private void getSavingsOutcomeList(final SavingsDataProxy savingsData, final OutcomeDataProxy outcomeDataProxy) {
		Request<List<OutcomeDataProxy>> req = clientFactory.getRequestFactory().getOutcomeDataRequest().getSavingsOutcomeList(outcomeDataProxy.getGroupKey());
		req.fire(new Receiver<List<OutcomeDataProxy>>() {
			public void onSuccess(List<OutcomeDataProxy> outcomeDataList) {
				if (outcomeDataList!=null)
					alterSavingsPlan(savingsData, outcomeDataList, outcomeDataProxy);
			}
			public void onFailure(ServerFailure error) {
				super.onFailure(error);
			}
		});

	}

	private void alterSavingsPlan(SavingsDataProxy savingsData,
			List<OutcomeDataProxy> savingsOutcomeList, final OutcomeDataProxy outcomeDataProxy) {

		List<OutcomeDataProxy> previousOutcomeList= new ArrayList<OutcomeDataProxy>();
		final List<OutcomeDataProxy> followingOutcomeList= new ArrayList<OutcomeDataProxy>();

		for(OutcomeDataProxy outcomeData:savingsOutcomeList){
			if(outcomeData.getDate().getTime()<outcomeDataProxy.getDate().getTime()){
				previousOutcomeList.add(outcomeData);
			}else if(outcomeData.getDate().getTime()>outcomeDataProxy.getDate().getTime()){
				followingOutcomeList.add(outcomeData);
			}
		}

		int periodCount=followingOutcomeList.size();
		Date dateAfterRemove = new Date(outcomeDataProxy.getDate().getTime());

		incrementMonth(dateAfterRemove);
		Date date =new Date(dateAfterRemove.getTime());
		Date endDate=new Date(savingsData.getEndDate().getTime());

		if (periodCount==0){
			view.showMessage(ViewMessages.ERROR_ON_DELETE);
			return;
		}

		float value =findValueToPay(savingsData,previousOutcomeList);
		float installmentValue=round(value/(float)periodCount);
		System.out.println("Warto�� raty: "+ installmentValue);


		date =new Date(dateAfterRemove.getTime());
		OutcomeDataRequest request= clientFactory.getRequestFactory().getOutcomeDataRequest();
		ArrayList <OutcomeDataProxy> outcomeDataListToSave=prepareOutcomeListForSavingsPlan(followingOutcomeList, installmentValue, savingsData, request,outcomeDataProxy);

		if(!outcomeDataListToSave.isEmpty()) {
			request.persistAllSavings(outcomeDataListToSave).fire(new Receiver<List<OutcomeDataProxy>>() {
				public void onSuccess(List<OutcomeDataProxy> returnedOutcomeData) {
					if(returnedOutcomeData==null || returnedOutcomeData.size()==0){
						view.showMessage(ViewMessages.ERROR_ON_PERSIST);
					}else{
						view.updateGrid(followingOutcomeList,returnedOutcomeData);
						deleteSingleOutcome(outcomeDataProxy);
					}

				}
				public void onFailure(ServerFailure error) {
					view.showMessage(ViewMessages.ERROR_ON_PERSIST);
					super.onFailure(error);
				}
			});    

		}else {
			view.showMessage(ViewMessages.ERROR_ON_PERSIST);
		}
	}


	private float findValueToPay(SavingsDataProxy savingsData,
			List<OutcomeDataProxy> outcomeDataList2) {
		float valuePaid=0;
		for(OutcomeDataProxy outcomeData:outcomeDataList2){
			valuePaid=outcomeData.getValue();
		}
		return (-savingsData.getValue()-valuePaid);
	}

	private void incrementMonth(Date date){
		if (date.getMonth()==11)
			date.setYear(date.getYear()+1);	
		date.setMonth((date.getMonth()+1)%12);
	}

	private ArrayList<OutcomeDataProxy> prepareOutcomeListForSavingsPlan(
			List<OutcomeDataProxy> followingOutcomeList, float value,
			SavingsDataProxy savingsData, OutcomeDataRequest request, OutcomeDataProxy outcomeDataProxy) {

		ArrayList<OutcomeDataProxy> outcomeListToEdit= new ArrayList<OutcomeDataProxy>();
		for(OutcomeDataProxy outcomeData:followingOutcomeList){
			OutcomeDataProxy data =  request.edit(outcomeData);
			data.setCategory(Constants.SAVINGS_CATEGORY);
			data.setDate(outcomeData.getDate());
			data.setMultiple(true);
			data.setName(savingsData.getName());
			data.setPriority(Constants.OUTCOME_PRIORITY_HIGH);
			data.setRepeatEndDate(savingsData.getEndDate());
			data.setRepeatInterval(Constants.OUTCOME_FREQUENCY_MONTH);
			data.setValue(value);
			data.setGroupKey(outcomeDataProxy.getGroupKey());
			outcomeListToEdit.add(data);

		}

		return outcomeListToEdit;

	}


	@Override
	public void goToOutcomeEditPlace(OutcomeDataProxy selectedItem) {
		OutcomeEditPlace place = new OutcomeEditPlace(selectedItem);
		goTo(place);
		
	}


}


